# -*- coding: utf-8 -*-
"""
Markdownify 转换工具类 - 使用 markdownify 库
提供全面的 Markdown 和 HTML 格式互转功能
"""
import re
import json
import hashlib
from typing import Optional, Dict, Any, List, Union
from urllib.parse import urlparse, urljoin
import logging

# 配置日志
logger = logging.getLogger(__name__)


class MarkdownifyConverter:
    """基于 markdownify 的 Markdown 和 HTML 转换工具类"""
    
    def __init__(self, config: Optional[Dict[str, Any]] = None):
        """
        初始化转换器
        
        Args:
            config: 配置字典
        """
        self.config = config or {}
        self._setup_markdownify()
        self._setup_extensions()
    
    def _setup_markdownify(self):
        """设置 markdownify"""
        try:
            import markdownify
            self.markdownify = markdownify
            self.markdownify_available = True
        except ImportError:
            logger.warning("markdownify 库未安装，将使用基础功能")
            self.markdownify_available = False
    
    def _setup_extensions(self):
        """设置 Markdown 扩展"""
        try:
            import markdown
            self.markdown = markdown
            
            # 默认扩展配置
            self.default_extensions = [
                'markdown.extensions.extra',           # 包含多个扩展
                'markdown.extensions.codehilite',      # 代码高亮
                #'markdown.extensions.toc',             # 目录生成
                'markdown.extensions.tables',          # 表格支持
                'markdown.extensions.fenced_code',     # 代码块
                'markdown.extensions.nl2br',           # 换行处理
                'markdown.extensions.sane_lists',      # 智能列表
                'markdown.extensions.smarty',          # 智能标点
                'markdown.extensions.footnotes',       # 脚注
                'markdown.extensions.def_list',        # 定义列表
                'markdown.extensions.abbr',            # 缩写
                'markdown.extensions.attr_list',       # 属性列表
                'markdown.extensions.md_in_html',      # HTML 中的 Markdown
                'markdown.extensions.wikilinks',       # Wiki 链接
            ]
            
            # 扩展配置
            self.extension_configs = {
                'markdown.extensions.codehilite': {
                    'css_class': 'highlight',
                    'use_pygments': True,
                    'noclasses': True,
                    'linenums': False,
                },
                'markdown.extensions.toc': {
                    'title': '目录',
                    'permalink': True,
                    'permalink_title': '永久链接',
                    'toc_depth': 6,
                },
                'markdown.extensions.smarty': {
                    'smart_angled_quotes': True,
                    'smart_quotes': True,
                    'smart_dashes': True,
                    'smart_ellipses': True,
                },
                'markdown.extensions.footnotes': {
                    'PLACE_MARKER': '///footnote///',
                }
            }
            
        except ImportError:
            logger.warning("markdown 库未安装，将使用基础功能")
            self.markdown = None
    
    def html_to_markdown(self,
                        html_text: str,
                        heading_style: str = 'ATX',
                        bullets: str = '-',
                        code_language: str = '',
                        strip: Optional[List[str]] = None,
                        wrap: bool = False,
                        wrap_width: int = 80,
                        **kwargs) -> str:
        """
        将 HTML 转换为 Markdown

        Args:
            html_text: HTML 文本
            heading_style: 标题样式 ('ATX', 'SETEXT')
            bullets: 列表符号 ('-', '*', '+')
            code_language: 代码块语言
            strip: 要移除的标签列表
            wrap: 是否自动换行
            wrap_width: 换行宽度
            **kwargs: 其他参数

        Returns:
            Markdown 文本
        """
        if not html_text:
            return ""

        if not self.markdownify_available:
            logger.warning("markdownify 库未安装，使用基础转换")
            return self._basic_html_to_markdown(html_text)

        try:
            # 创建 markdownify 实例
            md = self.markdownify.MarkdownConverter(
                heading_style=heading_style,
                bullets=bullets,
                code_language=code_language,
                strip=strip or [],
                wrap=wrap,
                wrap_width=wrap_width,
                **kwargs
            )

            # 转换
            markdown_result = md.convert(html_text)

            return markdown_result

        except Exception as e:
            logger.error(f"HTML 转 Markdown 失败: {e}")
            return self._basic_html_to_markdown(html_text)

    def markdown_to_html(self,
                        markdown_text: str,
                        extensions: Optional[List[str]] = None,
                        extension_configs: Optional[Dict[str, Dict]] = None,
                        output_format: str = 'html5',
                        **kwargs) -> str:
        """
        将 Markdown 转换为 HTML

        Args:
            markdown_text: Markdown 文本
            extensions: 扩展列表
            extension_configs: 扩展配置
            output_format: 输出格式 ('html5', 'xhtml1', 'xhtml')
            **kwargs: 其他参数

        Returns:
            HTML 文本
        """
        if not markdown_text:
            return ""

        if not self.markdown:
            logger.warning("markdown 库未安装，使用基础转换")
            return self._basic_markdown_to_html(markdown_text)

        try:
            # 使用配置的扩展
            ext_list = extensions or self.default_extensions
            ext_config = extension_configs or self.extension_configs

            # 验证扩展是否可用
            available_extensions = []
            for ext in ext_list:
                try:
                    __import__(ext)
                    available_extensions.append(ext)
                except ImportError:
                    logger.warning(f"扩展 {ext} 不可用，已跳过")

            if not available_extensions:
                logger.warning("没有可用的扩展，使用基础转换")
                return self._basic_markdown_to_html(markdown_text)

            # 创建 Markdown 实例
            md = self.markdown.Markdown(
                extensions=available_extensions,
                extension_configs=ext_config,
                output_format=output_format,
                **kwargs
            )

            # 转换
            html_result = md.convert(markdown_text)

            return html_result

        except Exception as e:
            logger.error(f"Markdown 转换失败: {e}")
            return self._basic_markdown_to_html(markdown_text)

    def convert_with_options(self,
                           text: str,
                           from_format: str = 'html',
                           to_format: str = 'markdown',
                           options: Optional[Dict[str, Any]] = None,
                           **kwargs) -> str:
        """
        使用选项进行格式转换

        Args:
            text: 输入文本
            from_format: 源格式 ('html', 'markdown')
            to_format: 目标格式 ('html', 'markdown')
            options: 转换选项
            **kwargs: 其他参数

        Returns:
            转换后的文本
        """
        options = options or {}

        if from_format.lower() == 'html' and to_format.lower() == 'markdown':
            return self.html_to_markdown(text, **options, **kwargs)
        elif from_format.lower() == 'markdown' and to_format.lower() == 'html':
            return self.markdown_to_html(text, **options, **kwargs)
        else:
            raise ValueError(f"不支持的转换: {from_format} -> {to_format}")

    def batch_convert(self,
                     texts: List[str],
                     from_format: str = 'html',
                     to_format: str = 'markdown',
                     options: Optional[Dict[str, Any]] = None,
                     **kwargs) -> List[str]:
        """
        批量转换文本

        Args:
            texts: 文本列表
            from_format: 源格式
            to_format: 目标格式
            options: 转换选项
            **kwargs: 其他参数

        Returns:
            转换后的文本列表
        """
        results = []
        for text in texts:
            try:
                result = self.convert_with_options(
                    text, from_format, to_format, options, **kwargs
                )
                results.append(result)
            except Exception as e:
                logger.error(f"批量转换失败: {e}")
                results.append(text)  # 返回原文

        return results

    def extract_links(self, html_text: str) -> List[Dict[str, str]]:
        """
        从 HTML 中提取链接

        Args:
            html_text: HTML 文本

        Returns:
            链接列表
        """
        links = []

        # 使用正则表达式提取链接
        link_pattern = r'<a[^>]*href=["\']([^"\']*)["\'][^>]*>(.*?)</a>'
        matches = re.findall(link_pattern, html_text, re.DOTALL | re.IGNORECASE)

        for url, text in matches:
            links.append({
                'url': url,
                'text': re.sub(r'<[^>]+>', '', text).strip(),
                'raw_text': text
            })

        return links

    def extract_images(self, html_text: str) -> List[Dict[str, str]]:
        """
        从 HTML 中提取图片

        Args:
            html_text: HTML 文本

        Returns:
            图片列表
        """
        images = []

        # 使用正则表达式提取图片
        img_pattern = r'<img[^>]*src=["\']([^"\']*)["\'][^>]*alt=["\']([^"\']*)["\'][^>]*/?>'
        matches = re.findall(img_pattern, html_text, re.IGNORECASE)

        for src, alt in matches:
            images.append({
                'src': src,
                'alt': alt,
                'url': src
            })

        return images

    def extract_tables(self, html_text: str) -> List[Dict[str, Any]]:
        """
        从 HTML 中提取表格

        Args:
            html_text: HTML 文本

        Returns:
            表格列表
        """
        tables = []

        # 使用正则表达式提取表格
        table_pattern = r'<table[^>]*>(.*?)</table>'
        table_matches = re.findall(table_pattern, html_text, re.DOTALL | re.IGNORECASE)

        for table_html in table_matches:
            # 提取表头
            headers = []
            header_pattern = r'<th[^>]*>(.*?)</th>'
            header_matches = re.findall(header_pattern, table_html, re.DOTALL | re.IGNORECASE)

            for header in header_matches:
                headers.append(re.sub(r'<[^>]+>', '', header).strip())

            # 提取行
            rows = []
            row_pattern = r'<tr[^>]*>(.*?)</tr>'
            row_matches = re.findall(row_pattern, table_html, re.DOTALL | re.IGNORECASE)

            for row_html in row_matches:
                cells = []
                cell_pattern = r'<td[^>]*>(.*?)</td>'
                cell_matches = re.findall(cell_pattern, row_html, re.DOTALL | re.IGNORECASE)

                for cell in cell_matches:
                    cells.append(re.sub(r'<[^>]+>', '', cell).strip())

                if cells:
                    rows.append(cells)

            tables.append({
                'headers': headers,
                'rows': rows,
                'html': table_html
            })

        return tables

    def clean_html(self,
                  html_text: str,
                  allowed_tags: Optional[List[str]] = None,
                  remove_scripts: bool = True,
                  remove_styles: bool = True,
                  **kwargs) -> str:
        """
        清理 HTML

        Args:
            html_text: HTML 文本
            allowed_tags: 允许的标签列表
            remove_scripts: 是否移除脚本
            remove_styles: 是否移除样式
            **kwargs: 其他参数

        Returns:
            清理后的 HTML
        """
        if not html_text:
            return ""

        cleaned_html = html_text

        # 移除脚本
        if remove_scripts:
            cleaned_html = re.sub(r'<script[^>]*>.*?</script>', '', cleaned_html, flags=re.DOTALL | re.IGNORECASE)
            cleaned_html = re.sub(r'<script[^>]*/?>', '', cleaned_html, flags=re.IGNORECASE)

        # 移除样式
        if remove_styles:
            cleaned_html = re.sub(r'<style[^>]*>.*?</style>', '', cleaned_html, flags=re.DOTALL | re.IGNORECASE)
            cleaned_html = re.sub(r'<style[^>]*/?>', '', cleaned_html, flags=re.IGNORECASE)

        # 移除危险属性
        dangerous_attrs = ['onclick', 'onload', 'onerror', 'onmouseover', 'javascript:']
        for attr in dangerous_attrs:
            cleaned_html = re.sub(rf'{attr}=["\'][^"\']*["\']', '', cleaned_html, flags=re.IGNORECASE)

        # 移除不允许的标签
        if allowed_tags:
            # 这里可以实现更复杂的标签过滤逻辑
            pass

        return cleaned_html

    def extract_text(self,
                    html_text: str,
                    preserve_formatting: bool = False,
                    **kwargs) -> str:
        """
        从 HTML 中提取纯文本

        Args:
            html_text: HTML 文本
            preserve_formatting: 是否保留格式
            **kwargs: 其他参数

        Returns:
            纯文本
        """
        if not html_text:
            return ""

        # 先转换为 Markdown，再提取文本
        markdown_text = self.html_to_markdown(html_text, **kwargs)
        
        if preserve_formatting:
            return markdown_text
        
        # 移除 Markdown 格式，只保留纯文本
        text = markdown_text
        
        # 移除标题标记
        text = re.sub(r'^#{1,6}\s+', '', text, flags=re.MULTILINE)
        
        # 移除粗体和斜体标记
        text = re.sub(r'\*\*(.+?)\*\*', r'\1', text)
        text = re.sub(r'\*(.+?)\*', r'\1', text)
        
        # 移除代码标记
        text = re.sub(r'`(.+?)`', r'\1', text)
        
        # 移除链接标记
        text = re.sub(r'\[([^\]]+)\]\([^)]+\)', r'\1', text)
        
        # 移除图片标记
        text = re.sub(r'!\[([^\]]*)\]\([^)]+\)', r'\1', text)
        
        # 移除列表标记
        text = re.sub(r'^[\s]*[-*+]\s+', '', text, flags=re.MULTILINE)
        text = re.sub(r'^[\s]*\d+\.\s+', '', text, flags=re.MULTILINE)
        
        # 移除引用标记
        text = re.sub(r'^>\s+', '', text, flags=re.MULTILINE)
        
        # 清理空白字符
        text = re.sub(r'\n\s*\n', '\n\n', text)
        text = text.strip()
        
        return text
    
    def validate_html(self, html_text: str) -> Dict[str, Any]:
        """
        验证 HTML
        
        Args:
            html_text: HTML 文本
            
        Returns:
            验证结果
        """
        result = {
            'valid': True,
            'errors': [],
            'warnings': [],
            'stats': {}
        }
        
        if not html_text:
            return result
        
        # 统计信息
        result['stats'] = {
            'total_tags': len(re.findall(r'<[^>]+>', html_text)),
            'links': len(self.extract_links(html_text)),
            'images': len(self.extract_images(html_text)),
            'tables': len(self.extract_tables(html_text)),
            'scripts': len(re.findall(r'<script[^>]*>', html_text, re.IGNORECASE)),
            'styles': len(re.findall(r'<style[^>]*>', html_text, re.IGNORECASE)),
        }
        
        # 检查未闭合的标签
        open_tags = re.findall(r'<([a-zA-Z][a-zA-Z0-9]*)[^>]*>', html_text)
        close_tags = re.findall(r'</([a-zA-Z][a-zA-Z0-9]*)>', html_text)
        
        # 简单的标签匹配检查
        for tag in set(open_tags):
            if tag not in ['img', 'br', 'hr', 'input', 'meta', 'link']:  # 自闭合标签
                open_count = open_tags.count(tag)
                close_count = close_tags.count(tag)
                if open_count != close_count:
                    result['warnings'].append(f'标签 <{tag}> 可能未正确闭合')
        
        # 检查危险内容
        dangerous_patterns = [
            (r'<script[^>]*>', '发现脚本标签'),
            (r'javascript:', '发现 JavaScript 协议'),
            (r'onclick=', '发现事件处理器'),
        ]
        
        for pattern, message in dangerous_patterns:
            if re.search(pattern, html_text, re.IGNORECASE):
                result['warnings'].append(message)
        
        return result 
    
    def _basic_html_to_markdown(self, html_text: str) -> str:
        """基础 HTML 转 Markdown 实现"""
        markdown = html_text
        
        # 处理标题
        for i in range(1, 7):
            markdown = re.sub(
                rf'<h{i}[^>]*>(.*?)</h{i}>', 
                rf'{"#" * i} \1\n', 
                markdown, 
                flags=re.DOTALL
            )
        
        # 处理粗体和斜体
        markdown = re.sub(r'<(strong|b)[^>]*>(.*?)</(strong|b)>', r'**\2**', markdown, flags=re.DOTALL)
        markdown = re.sub(r'<(em|i)[^>]*>(.*?)</(em|i)>', r'*\2*', markdown, flags=re.DOTALL)
        
        # 处理代码
        markdown = re.sub(r'<code[^>]*>(.*?)</code>', r'`\1`', markdown, flags=re.DOTALL)
        
        # 处理代码块
        markdown = re.sub(
            r'<pre[^>]*><code[^>]*>(.*?)</code></pre>', 
            r'```\n\1\n```', 
            markdown, 
            flags=re.DOTALL
        )
        
        # 处理链接
        markdown = re.sub(
            r'<a[^>]*href=["\']([^"\']*)["\'][^>]*>(.*?)</a>', 
            r'[\2](\1)', 
            markdown, 
            flags=re.DOTALL
        )
        
        # 处理图片
        markdown = re.sub(
            r'<img[^>]*src=["\']([^"\']*)["\'][^>]*alt=["\']([^"\']*)["\'][^>]*/?>', 
            r'![\2](\1)', 
            markdown
        )
        
        # 处理列表
        markdown = re.sub(r'<li[^>]*>(.*?)</li>', r'- \1', markdown, flags=re.DOTALL)
        
        # 处理引用
        markdown = re.sub(r'<blockquote[^>]*>(.*?)</blockquote>', r'> \1', markdown, flags=re.DOTALL)
        
        # 处理段落
        markdown = re.sub(r'<p[^>]*>(.*?)</p>', r'\1\n\n', markdown, flags=re.DOTALL)
        
        # 处理换行
        markdown = re.sub(r'<br[^>]*/?>', r'\n', markdown)
        
        # 处理分割线
        markdown = re.sub(r'<hr[^>]*/?>', r'---', markdown)
        
        # 清理多余的空白
        markdown = re.sub(r'\n\s*\n\s*\n', r'\n\n', markdown)
        markdown = markdown.strip()
        
        return markdown
    
    def _basic_markdown_to_html(self, markdown_text: str) -> str:
        """基础 Markdown 转 HTML 实现"""
        html = markdown_text
        
        # 处理标题
        for i in range(6, 0, -1):
            pattern = r'^' + '#' * i + r'\s+(.+)$'
            html = re.sub(pattern, rf'<h{i}>\1</h{i}>', html, flags=re.MULTILINE)
        
        # 处理粗体和斜体
        html = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', html)
        html = re.sub(r'\*(.+?)\*', r'<em>\1</em>', html)
        
        # 处理代码
        html = re.sub(r'`(.+?)`', r'<code>\1</code>', html)
        
        # 处理代码块
        html = re.sub(r'```(\w+)?\n(.*?)\n```', 
                     r'<pre><code class="language-\1">\2</code></pre>', 
                     html, flags=re.DOTALL)
        
        # 处理链接
        html = re.sub(r'\[([^\]]+)\]\(([^)]+)\)', r'<a href="\2">\1</a>', html)
        
        # 处理图片
        html = re.sub(r'!\[([^\]]*)\]\(([^)]+)\)', r'<img src="\2" alt="\1">', html)
        
        # 处理列表
        html = re.sub(r'^[\s]*[-*+]\s+(.+)$', r'<li>\1</li>', html, flags=re.MULTILINE)
        
        # 处理引用
        html = re.sub(r'^>\s+(.+)$', r'<blockquote>\1</blockquote>', html, flags=re.MULTILINE)
        
        # 处理分割线
        html = re.sub(r'^[-*_]{3,}$', r'<hr>', html, flags=re.MULTILINE)
        
        # 处理段落
        html = re.sub(r'\n\s*\n', r'</p>\n<p>', html)
        html = f'<p>{html}</p>'
        
        # 包装列表项
        html = re.sub(r'(<li>.*?</li>)', r'<ul>\1</ul>', html, flags=re.DOTALL)
        
        return html


# 创建全局实例
markdownify_converter = MarkdownifyConverter()


# 便捷函数
def html_to_markdown_markdownify(text: str, **kwargs) -> str:
    """使用 markdownify 将 HTML 转换为 Markdown"""
    return markdownify_converter.html_to_markdown(text, **kwargs)


def markdown_to_html_markdownify(text: str, **kwargs) -> str:
    """将 Markdown 转换为 HTML"""
    return markdownify_converter.markdown_to_html(text, **kwargs)


def convert_with_markdownify(text: str, from_format: str = 'html', to_format: str = 'markdown', **kwargs) -> str:
    """使用 markdownify 进行格式转换"""
    return markdownify_converter.convert_with_options(text, from_format, to_format, **kwargs)


def batch_convert_markdownify(texts: List[str], from_format: str = 'html', to_format: str = 'markdown', **kwargs) -> List[str]:
    """批量转换"""
    return markdownify_converter.batch_convert(texts, from_format, to_format, **kwargs)


def extract_links_markdownify(text: str) -> List[Dict[str, str]]:
    """提取链接"""
    return markdownify_converter.extract_links(text)


def extract_images_markdownify(text: str) -> List[Dict[str, str]]:
    """提取图片"""
    return markdownify_converter.extract_images(text)


def extract_tables_markdownify(text: str) -> List[Dict[str, Any]]:
    """提取表格"""
    return markdownify_converter.extract_tables(text)


def clean_html_markdownify(text: str, **kwargs) -> str:
    """清理 HTML"""
    return markdownify_converter.clean_html(text, **kwargs)


def extract_text_markdownify(text: str, **kwargs) -> str:
    """提取纯文本"""
    return markdownify_converter.extract_text(text, **kwargs)


def validate_html_markdownify(text: str) -> Dict[str, Any]:
    """验证 HTML"""
    return markdownify_converter.validate_html(text) 